/*
 * ServiceImpl.java
 */

package org.opencube.data.ws;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Properties;

import javax.servlet.http.HttpSession;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.server.ServiceLifecycle;
import javax.xml.rpc.server.ServletEndpointContext;

import org.apache.log4j.Logger;
import org.opencube.data.BoundVariable;
import org.opencube.data.CallResult;
import org.opencube.data.DataSource;
import org.opencube.data.RecordSet;

/**
 * Implementation class of remote <code>DataSourceService</code> interface.
 */
public class ServiceImpl implements DataSourceService, ServiceLifecycle
{
	private ServletEndpointContext context = null;
	private static final String ATT_DATA_SOURCE = "DATA_SOURCE"; 
	private static Properties dsProperties = null;
	private static Logger logger = Logger.getLogger( ServiceImpl.class );

	/* (non-Javadoc)
	 * @see org.opencube.data.ws.DataSourceService#commit()
	 */
	public void commit() throws RemoteException
	{
		try
		{
			getDataSource().commit();
		}
		catch( Exception e )
		{
			logger.error( "Exception occured while 'commit()' execution: " + e.getMessage() );
			throw new RemoteException( "Exception occured while 'commit()' execution: " + e.getMessage(), e );
		}
	}

	/* (non-Javadoc)
	 * @see org.opencube.data.ws.DataSourceService#execute(java.lang.String)
	 */
	public boolean execute( String statement ) throws RemoteException
	{
		try
		{
			return getDataSource().execute( statement );
		}
		catch( Exception e )
		{
			logger.error( "Exception occured while 'execute()' execution: " + e.getMessage() + ". Statement: '" + statement + "'" );
			throw new RemoteException( "Exception occured while 'execute()' execution: " + e.getMessage() + ". Statement: '" + statement + "'", e );
		}
	}

	/* (non-Javadoc)
	 * @see org.opencube.data.ws.DataSourceService#executeCall(java.lang.String, org.opencube.data.ws.entity.BoundVariable[])
	 */
	public CallResult executeCall( String statement, BoundVariable[] bindVariables )
	throws RemoteException
	{
		try
		{
			return getDataSource().executeCall( statement, bindVariables );
		}
		catch( Exception e )
		{
			logger.error( "Exception while 'executeCall' execution: " + e.getMessage() + ". Statement: '" + statement + "'" );
			throw new RemoteException( "Exception while 'executeCall' execution: " + e.getMessage() + ". Statement: '" + statement + "'", e );
		}
	}

	public int executeBatch(String statement, BoundVariable[][] boundVariables)
	throws RemoteException
	{
		try
		{
			return getDataSource().executeBatch( statement, boundVariables );
		}
		catch( Exception e )
		{
			logger.error( "Exception while 'executeBatch' execution: " + e.getMessage() + ". Statement: '" + statement + "'" );
			throw new RemoteException( "Exception while 'executeBatch' execution: " + e.getMessage() + ". Statement: '" + statement + "'", e );
		}
	}
	
	public int getMinimumBatchSize() throws RemoteException
	{
		try
		{
			return getDataSource().getMinimumBatchSize();
		}
		catch( Exception e )
		{
			logger.error( "Exception while 'getMinimumBatchSize' execution: " + e.getMessage() );
			throw new RemoteException( "Exception while 'getMinimumBatchSize' execution: " + e.getMessage(), e );
		}
	}
	
	public boolean supportsBatching() throws RemoteException
	{
		try
		{
			return getDataSource().supportsBatching();
		}
		catch( Exception e )
		{
			logger.error( "Exception while 'getMinimumBatchSize' execution: " + e.getMessage() );
			throw new RemoteException( "Exception while 'getMinimumBatchSize' execution: " + e.getMessage(), e );
		}
	}

	/* (non-Javadoc)
	 * @see org.opencube.data.ws.DataSourceService#executeQuery(java.lang.String)
	 */
	public RecordSet executeQuery( String query ) throws RemoteException
	{
		try
		{
			return getDataSource().executeQuery( query );
		}
		catch( Exception e )
		{
			logger.error( "Exception occured while 'executeQuery()' execution: " + e.getMessage() + ". Query: '" + query + "'" );
			throw new RemoteException( "Exception occured while 'executeQuery()' execution: " + e.getMessage() + ". Query: '" + query + "'", e );
		}
	}

	/* (non-Javadoc)
	 * @see org.opencube.data.ws.DataSourceService#executeUpdate(java.lang.String)
	 */
	public int executeUpdate( String statement ) throws RemoteException
	{
		try
		{
			return getDataSource().executeUpdate( statement );
		}
		catch( Exception e )
		{
			logger.error( "Exception occured while 'executeUpdate()' execution: " + e.getMessage() + ". Statement: '" + statement + "'" );
			throw new RemoteException( "Exception occured while 'executeUpdate()' execution: " + e.getMessage() + ". Statement: '" + statement + "'", e );
		}
	}

	/* (non-Javadoc)
	 * @see org.opencube.data.ws.DataSourceService#isAutoCommit()
	 */
	public boolean isAutoCommit() throws RemoteException
	{
		try
		{
			return getDataSource().isAutoCommit();
		}
		catch( Exception e )
		{
			logger.error( "Exception occured while 'isAutoCommit()' execution: " + e.getMessage() );
			throw new RemoteException( "Exception occured while 'isAutoCommit()' execution: " + e.getMessage(), e );
		}
	}

	/* (non-Javadoc)
	 * @see org.opencube.data.ws.DataSourceService#rollback()
	 */
	public void rollback() throws RemoteException
	{
		try
		{
			getDataSource().rollback();
		}
		catch( Exception e )
		{
			logger.error( "Exception occured while 'rollback()' execution: " + e.getMessage() );
			throw new RemoteException( "Exception occured while 'rollback()' execution: " + e.getMessage(), e );
		}
	}

	/* (non-Javadoc)
	 * @see org.opencube.data.ws.DataSourceService#setAutoCommit(boolean)
	 */
	public void setAutoCommit( boolean autoCommit ) throws RemoteException
	{
		try
		{
			getDataSource().setAutoCommit( autoCommit );
		}
		catch( Exception e )
		{
			logger.error( "Exception occured while 'setAutoCommit()' execution: " + e.getMessage() );
			throw new RemoteException( "Exception occured while 'setAutoCommit()' execution: " + e.getMessage(), e );
		}
	}
	
	private DataSource getDataSource() throws Exception
	{	
		HttpSession session = context.getHttpSession();
		logger.debug( "SESSION CREATION TIME: " + session.getCreationTime() );
		logger.debug( "SESSION ID: " + session.getId() );
		DataSource dataSource = (DataSource) session.getAttribute( ATT_DATA_SOURCE );
		if( dataSource == null )
		{
			logger.info( "DATA SOURCE INITIALIZATION: " );
			String className = dsProperties.getProperty( PROPERTY_DS_CLASS );
			logger.info( "INSTANTIATION OF THE '" + className + "' IMPLEMENTATION OF DATA SOURCE" );
			dataSource = (DataSource) Class.forName( className ).newInstance();
			logger.info( "INSTANTIATED" );
			logger.info( "CONNECTING DATA SOURCE: " );
			
			dataSource.connect( dsProperties );
			logger.info( "CONNECTED" );
			session.setAttribute( ATT_DATA_SOURCE, dataSource );
		}
		return dataSource;
	}
	/* (non-Javadoc)
	 * @see javax.xml.rpc.server.ServiceLifecycle#destroy()
	 */
	public void destroy()
	{
	}

	/* (non-Javadoc)
	 * @see javax.xml.rpc.server.ServiceLifecycle#init(java.lang.Object)
	 */
	public void init(Object arg0) throws ServiceException
	{
		
		context = (ServletEndpointContext) arg0;
		String propsPath = context.getServletContext().getInitParameter( PARAM_PROPERTIES_FILE_NAME );
		propsPath = context.getServletContext().getRealPath( propsPath );
		dsProperties = new Properties();
		try
		{
			dsProperties.load( new FileInputStream( propsPath ) );
			logger.info( "LOADED PROPERTIES FROM '" + propsPath + "'" );
			
		}
		catch( FileNotFoundException e )
		{
			logger.error( "The properties file '" + propsPath + "' not found: " + e.getMessage() );
			throw new ServiceException( "The properties file '" + propsPath + "' not found: " + e.getMessage(), e );
		}
		catch( IOException e )
		{
			logger.error( "The IO error occured while '" + propsPath + "' properties loading: " + e.getMessage() );
			throw new ServiceException( "The IO error occured while '" + propsPath + "' properties loading: " + e.getMessage(), e );
		}
	}
}
